package pl.edu.pw.elka.tinyrepo.gate.descriptor;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * Struktura kolejki priorytetowej do przechowywania deskryptorow
 * serwerow danych. Jest potrzebna tylko z tego powodu, ze
 * standardowe PriorityQueue nie pozwala na updateowanie
 * wartosci w niej sie znajdujacych. Kolejka typu min wzgl diskUsage w DataServerDescriptor.
 * TODO na operacje dodawania i aktualizacji zrobione w czasie
 * liniowym, zastosowano jako reprezentacje posortowana liste. Sprobowac zmienic na 
 * to wydajnosc. 
 *  
 * @author Piotr Jarosik
 */
class DataServerPriorityQueue {
   private List<DataServerDescriptor> sortedList = new ArrayList<DataServerDescriptor>();
   
   boolean contains(DataServerDescriptor d) {
      return sortedList.contains(d);
   }
   
   /**
    * Aktualizuje strukture kolejki priorytetowej. 
    * FIXME zrobione bardzo silowo, miejsce potencjalnej poprawy wydajnosci.
    * Tylko ze liczba DSow bedzie na razie mala, wiec w zupelnosci to na obecna
    * chwile wystarczy :)
    */
   void repair() {
      Collections.sort(sortedList); // FIXME zrobiono silowo, miejsce potencjalnej optymalizacji (do O(n)) 
   }
   
   /**
    * Dodaje element do kolejki priorytetowej.
    * FIXME zrobione bardzo silowo, miejsce potencjalnej poprawy wydajnosci 
    *  
    * @param d
    */
   void push(DataServerDescriptor d) {
      sortedList.add(d);
      Collections.sort(sortedList);
   }
   
   /**
    * @return deskryptor o minimalnym obciazeniu lub null, gdy kolejka pusta.
    */
   DataServerDescriptor peek() {
      if(sortedList.size() != 0)
         return sortedList.get(0);
      return null;
   }
   
   /**
    * Zwraca najlepszy DS i usuwa go z poczatku kolejki.
    * 
    * @return
    */
   DataServerDescriptor pop() {
      DataServerDescriptor d = peek();
      sortedList.remove(0);
      return d;
   }
   
   /**
    * @param hostName
    * @return deskryptor serwera danych albo null gdy takiego nie ma w kolejce
    */
   DataServerDescriptor get(String hostName) {
      for(DataServerDescriptor d : sortedList) 
         if(d.getHostName().equals(hostName))
            return d;
      return null;
   }
   
   /**
    * 
    * @param hostName
    * @return
    */
   boolean remove(String hostName) {
      int i = 0;
      for(i = 0; i < sortedList.size(); i++) // FIXME trzeba przejrzec cala liste, bo hostName nie jest kluczem 
         if(sortedList.get(i).getHostName().equals(hostName)) {
            sortedList.remove(i);
//            repair(); // trzeba jeszcze naprawic strukture kolejki - DLA SORTED list nie trzeba
            return true;
         }
      return false;
   }
      
   @Override
   public String toString() {
      return sortedList.toString();
   }
   
   // metody do realizacji kopca.
   @Deprecated
   private int left(int p) {
      return 2*p+1;
   }
   
   @Deprecated
   private int right(int p) {
      return 2*p+2;
   }
   
   @Deprecated
   private int parent(int p) {
      return (p-1)/2;
   }
   
   @Deprecated
   private void pushUp(int i) {
      while (i > 0 && sortedList.get(parent(i)).getDiskUsage() > sortedList.get(i).getDiskUsage()) { // kolejka typu min
         swap(parent(i), i);
         i = parent(i);
     }
   }
   
   @Deprecated
   private void pushDown(int i) {
      int l = left(i), r = right(i), best = i;
      if (l < sortedList.size() && sortedList.get(l).getDiskUsage() < sortedList.get(i).getDiskUsage()) {
          best = l;
      }
      if (r < sortedList.size() && sortedList.get(i).getDiskUsage() < sortedList.get(i).getDiskUsage()) {
          best = r;
      }

      if (best != i) {
          swap(best, i);
          pushDown(best);
      }
   }
   
   @Deprecated
   private void swap(int i, int j) {
      DataServerDescriptor tmp = sortedList.get(i);
      sortedList.set(i, sortedList.get(j));
      sortedList.set(j, tmp);
   }
}
